package api

import (
	"github.com/gin-gonic/gin"
	"github.com/thoas/go-funk"
	"go.uber.org/zap"
	"seat-service/initialization"
	"seat-service/model"
	"seat-service/model/dto"
	"seat-service/response"
	service "seat-service/service/impl"
	"seat-service/utils"
	"strconv"
	"strings"
)

var userService service.UserService
var resp response.CustomResponse
var jwt utils.JWT

type UserApi struct {
}

func (*UserApi) Me(c *gin.Context) {

	par, _ := c.Get("id")
	id := par.(uint)
	user, err := userService.GetById(id)
	if err != nil {
		initialization.SeatLogger.Error("userService.GetById(id) failed ", zap.Error(err))
		resp.Fail(c, response.CodeServerBusy, nil)
		return
	}

	//查询当前登录用户的角色
	casbinInformation, _ := casbinService.GetRoleName(user.RoleCode)
	//将角色名称提出 TODO
	roleNames := funk.Map(casbinInformation, func(role model.CasbinRuleExtended) string {
		return role.V1
	}).([]string)
	roleNameStr := strings.Join(roleNames, " ")
	data := dto.MeResponse{
		UserID:   user.ID,
		Username: user.Username,
		Nickname: user.Nickname,
		Avatar:   user.Avatar,
		Role:     roleNameStr,
	}
	buttons, err := menuService.GetButtonMenusByRoleAndType(data.Role)
	if err != nil {
		initialization.SeatLogger.Error("menuService.GetMenusByRoleAndType(data.Role, 4)) failed ", zap.Error(err))
		resp.Fail(c, response.CodeServerBusy, nil)
		return
	}
	for _, button := range buttons {
		data.Perms = append(data.Perms, button.Perm)
	}
	resp.Success(c, response.CodeSuccess, data)
}

func (*UserApi) Save(c *gin.Context) {
	par := &model.User{}
	if err := c.ShouldBind(par); err != nil {
		initialization.SeatLogger.Error("c.ShouldBind(par) failed", zap.Error(err))
		resp.Fail(c, response.CodeParamError, nil)
		return
	}

	if par.ID == 0 {
		if err := userService.Create(par); err != nil {
			initialization.SeatLogger.Error("userService.Create(par) failed ", zap.Error(err))
			resp.Fail(c, response.CodeServerBusy, nil)
			return
		}
	} else {
		if err := userService.Updates(par); err != nil {
			initialization.SeatLogger.Error("userService.Save(par) failed ", zap.Error(err))
			resp.Fail(c, response.CodeServerBusy, nil)
			return
		}
	}

	resp.Success(c, response.CodeSuccess, nil)
}

func (*UserApi) Delete(c *gin.Context) {
	par := c.QueryArray("ids")
	ids := make([]int, len(par))
	for i, s := range par {
		ids[i], _ = strconv.Atoi(s)
	}

	if err := userService.Deletes(ids); err != nil {
		initialization.SeatLogger.Error("userService.Delete(id) failed ", zap.Error(err))
		resp.Fail(c, response.CodeServerBusy, nil)
		return
	}
	resp.Success(c, response.CodeSuccess, nil)
}

// GetAll 获取所有用户
func (u *UserApi) GetAll(c *gin.Context) {
	param := &dto.ParamUserAdmin{}
	if err := c.ShouldBind(param); err != nil {
		initialization.SeatLogger.Error("c.ShouldBind(page) failed ", zap.Error(err))
		resp.Fail(c, response.CodeParamError, nil)
		return
	}
	users, err := userService.GetAllWithLike(param)
	if err != nil {
		initialization.SeatLogger.Error("userService.GetAll() failed ", zap.Error(err))
		resp.Fail(c, response.CodeServerBusy, nil)
		return
	}
	// 参数转换d
	data := []dto.UserResponse{}
	for _, user := range users {
		tmp, err := ToUserResponse(user)
		if err != nil {
			continue
		}
		data = append(data, tmp)
	}
	type respParam struct {
		Users []dto.UserResponse
		Total int64 `json:"total"`
	}
	res := respParam{
		Users: data,
		Total: userService.GetAllLen(),
	}
	resp.Success(c, response.CodeSuccess, res)
}

// Login 用户登录
func Login(c *gin.Context) {
	user := &model.User{}
	if err := c.ShouldBind(user); err != nil {
		initialization.SeatLogger.Error("c.ShouldBind(u) failed ", zap.Error(err))
		resp.Fail(c, response.CodeParamError, nil)
		return
	}

	uu, err := userService.Login(user)
	if err != nil {
		initialization.SeatLogger.Error("c.ShouldBind(u) failed ", zap.Error(err))
		resp.Fail(c, response.AccountOrPasswordIsError, nil)
		return
	}

	if uu.ID == 0 {
		resp.Fail(c, response.AccountOrPasswordIsError, nil)
		return
	}
	userClaims := utils.UserClaims{
		Username: uu.Username,
		ID:       uu.ID,
		RoleCode: uu.RoleCode,
	}
	token, err := jwt.GenToken(userClaims)
	if err != nil {
		initialization.SeatLogger.Error("jwt.GenToken(userClaims) failed", zap.Error(err))
		resp.Fail(c, response.CodeServerBusy, nil)
		return
	}
	// 创建包含 token 的结构体实例
	respToken := struct{ Token string }{
		Token: token,
	}
	resp.Success(c, response.CodeSuccess, respToken)
}

var (
	gender = map[int]string{0: "未知", 1: "男", 2: "女"}
	state  = map[int]string{0: "启用", 1: "禁用"}
)

func ToUserResponse(u model.User) (user dto.UserResponse, err error) {
	role, err := casbinService.GetRoleByUserCode(u.RoleCode)
	var roleName string
	for _, value := range role {
		roleName = value.V1 + " " + roleName
	}
	if err != nil {
		return
	}
	user = dto.UserResponse{
		ID:          u.ID,
		Username:    u.Username,
		Nickname:    u.Nickname,
		GenderLabel: gender[u.Gender],
		Mobile:      u.Mobile,
		Status:      u.State,
		Email:       u.Email,
		RoleNames:   roleName,
		CreateTime:  u.CreatedAt.Format("2006-01-02"),
	}
	return
}
